package com.pb.infra.taskManage.service;


import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.pb.infra.oth.entity.common.DictVO;
import com.pb.infra.oth.entity.common.Result;
import com.pb.infra.oth.util.CDRCBFileEncryptionRest;
import com.pb.infra.oth.util.ExcelUtil;
import com.pb.infra.oth.util.ExportExcelUtil;
import com.pb.infra.taskManage.entity.MaJobCfg;
import com.pb.infra.taskManage.entity.MaJobEventCfg;
import com.pb.infra.taskManage.entity.MaJobRelyCfg;
import com.pb.infra.taskManage.mapper.MaJobCfgMapper;
import com.pb.infra.taskManage.mapper.MaJobEventCfgMapper;
import com.pb.infra.taskManage.mapper.MaJobRelyCfgMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.openxml4j.util.ZipSecureFile;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

/**
 * (MaJobRelyCfg)表服务实现类
 *
 * @author JYF
 * @since 2022-12-05 09:04:18
 */
@Slf4j
@Service("maJobRelyCfgService")
public class MaJobRelyCfgService {

    /**
     * 每页条数
     */
    final static int PAGE_SIZE = 50;

    private final static String[] COLNAMES = {"任务ID", "准备任务ID", "批次ID"};

    @Resource
    private MaJobRelyCfgMapper maJobRelyCfgMapper;

    @Resource
    private MaJobEventCfgMapper maJobEventCfgMapper;


    @Resource
    private MaJobCfgMapper maJobCfgMapper;

    @Resource
    private CDRCBFileEncryptionRest cdrcbFileEncryptionRest;

    public Result jobRelyImport(MaJobRelyCfg maJobRelyCfg, MultipartHttpServletRequest multipartHttpServletRequest) {
        InputStream input = null;
        try {
            MultipartFile excelFile = multipartHttpServletRequest.getFile("excel-file");
            input = cdrcbFileEncryptionRest.fileDecryption(excelFile.getInputStream());;
            XSSFWorkbook workbook = new XSSFWorkbook(input);
            Object checkMap = this.jobRelyCheck(maJobRelyCfg, workbook, 1, 1);
            if (checkMap instanceof String) {
                //检查未通过
                return Result.error("-1", checkMap.toString());
            } else {
                //检查通过
                Map checkList = (Map) checkMap;
                List<MaJobRelyCfg> dataList = (List<MaJobRelyCfg>) checkList.get("dataList");
                importJobRelyAdd(dataList, maJobRelyCfg.getAddType(),maJobRelyCfg.getSysNo());


                String rightInfo = checkList.get("rightInfo").toString();

                return Result.ok(rightInfo);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Result.error("-1", "导入失败");
        } finally {

            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 批量添加任务
     * @param dataList 数据
     * @param addType 添加模式类型（0.增量添加，1.覆盖添加），
     * @param sysNo 批次号
     */
    @Transactional
    public void importJobRelyAdd(List<MaJobRelyCfg> dataList,String addType,String sysNo) {

        List<List<MaJobRelyCfg>> listMaps = new ArrayList<>();
        int page = 0;

        if (dataList.size() % PAGE_SIZE == 0) {
            page = dataList.size() / PAGE_SIZE;
        } else {
            page = dataList.size() / PAGE_SIZE + 1;
        }
        //page等于开启的线程数
        for (int i = 0; i < page; i++) {
            listMaps.add(dataList.stream().skip(PAGE_SIZE * i).limit(PAGE_SIZE).collect(Collectors.toList()));
        }

        //覆盖添加
        if (addType.equals("1")){
            maJobRelyCfgMapper.delete(sysNo);
        }

        listMaps.forEach(item->{
            maJobRelyCfgMapper.insertBatch(item);
        });
    }
    private Object jobRelyCheck(MaJobRelyCfg maJobRelyCfg, XSSFWorkbook workbook, int startRowNum, int sheetCount) {
        List<List<DictVO>> dictList = new ArrayList<>();
        MaJobEventCfg maJobEventCfg = new MaJobEventCfg();
        maJobEventCfg.setGroupName(maJobRelyCfg.getSysNo());

        //批次列表
        dictList.add(maJobCfgMapper.queryDictList(new MaJobCfg()));

        //任务列表
        dictList.add(maJobEventCfgMapper.queryDictList(maJobEventCfg));


        List<String[]> importDataList = new ArrayList<>();   //导入list数据集合
        boolean hasErr = false;                              //存在错误标志位
        StringBuilder errInfo = new StringBuilder();         //全局错误信息
        StringBuilder rowErrInfo;                            //行错误信息
        StringBuilder valErrInfo;                            //单元格错误信息

        HashSet<String> primaryKeySet = new HashSet<>();     //主键集（辅助检查主键是否重复）
        String primeKey;                                     //每行主键值
        DataFormatter formatter = new DataFormatter();
        ZipSecureFile.setMinInflateRatio(-1.0d);
        errInfo.append("<br/>");
        errInfo.append("**********   <span style='color:red;font-weight:bold;'>导入结果：失败</span>   **********");
        if (workbook.getNumberOfSheets() < sheetCount) {
            //如果导入文件工作簿数不足，则记录错误信息，返回
            errInfo.append("<br/><br/><br/>工作簿不足，导入文件应具备" + sheetCount + "个工作簿，请使用模板导入");
            return errInfo.toString();
        }
        //遍历工作薄
        errInfo.append("<br/><br/><br/>*** 开始检查工作簿一 ***");
        XSSFSheet sheet = workbook.getSheetAt(0);
        int totalCellCount = COLNAMES.length;


        for (int i = startRowNum; i <= sheet.getLastRowNum(); i++) {
            //遍历每一行（从工作簿第startDataRow行开始读取）
            XSSFRow row = sheet.getRow(i);
            if (row != null && !ExcelUtil.concatString(row, totalCellCount, formatter)) {
                //行数据错误标志位
                boolean rowErr = false;
                rowErrInfo = new StringBuilder();
                String[] importData = new String[totalCellCount];    //利率基本信息数据
                rowErrInfo.append("<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;第 ").append(i + 1).append(" 行：");

                //便利每列数据
                for (int j = 0; j < totalCellCount; j++) {
                    //遍历每一个单元格
                    XSSFCell cell = row.getCell(j);

                    //校验数据
                    valErrInfo = this.jobRelyDataValidate(ExcelUtil.getStringCellValues(formatter, cell), i, j + 1, dictList,importData);
                    if (valErrInfo.length() != 0) {
                        rowErrInfo.append(valErrInfo);
                        rowErr = true;
                        hasErr = true;
                    } else {
                        //每行数据
                        importData[j] = ExcelUtil.getStringCellValues(formatter, cell);
                    }

                }

                importDataList.add(importData);

                if (rowErr) {
                    //将行错误信息记录到全局错误信息中
                    errInfo.append(rowErrInfo.toString());
                }


            }
        }
        //返回最终结果
        if (hasErr) {
            return errInfo.toString();
        } else {
            StringBuilder rightInfo = new StringBuilder();
            rightInfo.append("<br/>");
            rightInfo.append("**********   <span style='color:green;font-weight:bold;'>导入结果：成功</span>   **********");
            rightInfo.append("<br/><br/>共计导入 <span style='color:blue;font-weight:bold;'>" + importDataList.size() + "</span> 条 任务配置数据");
            Map<String, Object> mapList = new HashMap<>();
            mapList.put("dataList", this.jobRelyDataFormat(maJobRelyCfg, importDataList));
            mapList.put("rightInfo", rightInfo.toString());
            mapList.put("rateTerm", COLNAMES);
            return mapList;
        }
    }

    private Object jobRelyDataFormat(MaJobRelyCfg maJobRelyCfg, List<String[]> importDataList) {
        List<MaJobRelyCfg> list = new ArrayList<>();
        for (String[] item :
                importDataList) {
            MaJobRelyCfg maJobEventCfg = new MaJobRelyCfg();


            for (int i = 0; i < item.length; i++) {
                switch (i) {
                    case 0:
                        maJobEventCfg.setJobId(item[i]);
                        break;
                    case 1:
                        maJobEventCfg.setRelyJobId(item[i]);
                        break;
                    case 2:
                        maJobEventCfg.setSysNo(item[i]);
                }
            }
            list.add(maJobEventCfg);
        }

        return list;
    }

    private StringBuilder jobRelyDataValidate(String data, int row, int col, List<List<DictVO>> dictList,String[] rowData) {

        StringBuilder rowErrInfo = new StringBuilder();


        switch (col) {
            case 1:
                //任务ID
                if (data == null && data.trim().isEmpty()) {
                    rowErrInfo.append("<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;第").append(col).append("列 第<").append(row).append(">行 任务ID，不能为空。");
                } else {
                    boolean isValid = dictList.get(1).stream().anyMatch(item -> item.getValue().equals(data));
                    if (!isValid) {
                        rowErrInfo.append("<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;第").append(col).append("列 第<").append(row).append(">行 任务ID 不存在");
                    }
                }
                break;
            case 2:
                //准备任务ID
                if (data == null && data.trim().isEmpty()) {
                    rowErrInfo.append("<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;第").append(col).append("列 第<").append(row).append(">行 准备任务ID，不能为空。");
                } else if (data.equals(rowData[0])) {
                    rowErrInfo.append("<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;第").append(col).append("列 第<").append(row).append(">行 准备任务ID，不能与任务ID相同。");
                } else {
                    boolean isValid = dictList.get(1).stream().anyMatch(item -> item.getValue().equals(data));
                    if (!isValid) {
                        rowErrInfo.append("<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;第").append(col).append("列 第<").append(row).append(">行 准备任务ID 不存在");
                    }
                }
                break;
            case 3:
                //批次ID
                boolean isValid = dictList.get(0).stream().anyMatch(item -> item.getValue().equals(data));
                if (!isValid) {
                    rowErrInfo.append("<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;第").append(col).append("列 第<").append(row).append(">行 批次ID 不存在");
                }
                break;


        }


        return rowErrInfo;
    }

    /**
     * 任务关系配置--导出
     *
     * @param maJobRelyCfg 筛选条件
     * @param response     响应
     */
    public void jobRelyExport(MaJobRelyCfg maJobRelyCfg, HttpServletResponse response) {

        HorizontalCellStyleStrategy horizontalCellStyleStrategy =
                new HorizontalCellStyleStrategy(ExportExcelUtil.headerStyle(), ExportExcelUtil.mainStyle());

        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("任务关系列表", "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            // 这里需要设置不关闭流

            List<Map<String, String>> sheetList = new ArrayList<>();

            Map<String, String> map1 = new HashMap<>();
            map1.put("code", "1");
            map1.put("sheetName", "");

            Map<String, String> map2 = new HashMap<>();
            map2.put("code", "2");
            map2.put("sheetName", "");

            sheetList.add(map1);
            sheetList.add(map2);


            ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).registerWriteHandler(horizontalCellStyleStrategy).build();

            WriteSheet writeSheet = EasyExcel.writerSheet(0, "任务关系列表").head(MaJobRelyCfg.class).build();
            excelWriter.write(this.maJobRelyCfgMapper.queryList(maJobRelyCfg), writeSheet);


            // 每次都要创建writeSheet 这里注意必须指定sheetNo 而且sheetName必须不一样
            WriteSheet writeCodeSheet1 = EasyExcel.writerSheet(1, "批次列表").head(DictVO.class).build();
            excelWriter.write(maJobCfgMapper.queryDictList(new MaJobCfg()), writeCodeSheet1);

            WriteSheet writeCodeSheet2 = EasyExcel.writerSheet(2, "任务列表").head(DictVO.class).build();
            MaJobEventCfg maJobEventCfg = new MaJobEventCfg();
            maJobEventCfg.setGroupName(maJobRelyCfg.getSysNo());
            excelWriter.write(maJobEventCfgMapper.queryDictList(maJobEventCfg), writeCodeSheet2);



            excelWriter.finish();
        } catch (IOException e) {
            e.printStackTrace();
            // 重置response
            response.reset();
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");

        }
    }



}
